/*
给你一个整数数组 arr 。

现需要从数组中取三个下标 i、j 和 k ，其中 (0 <= i < j <= k < arr.length) 。

a 和 b 定义如下：

a = arr[i] ^ arr[i + 1] ^ ... ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ ... ^ arr[k]
注意：^ 表示 按位异或 操作。

请返回能够令 a == b 成立的三元组 (i, j , k) 的数目。

 

示例 1：

输入：arr = [2,3,1,6,7]
输出：4
解释：满足题意的三元组分别是 (0,1,2), (0,2,2), (2,3,4) 以及 (2,4,4)
示例 2：

输入：arr = [1,1,1,1,1]
输出：10
示例 3：

输入：arr = [2,3]
输出：0
示例 4：

输入：arr = [1,3,5,7,9]
输出：3
示例 5：

输入：arr = [7,11,12,9,5,2,7,17,22]
输出：8
 

提示：

1 <= arr.length <= 300
1 <= arr[i] <= 10^8

*/

#include "stdc++.h"

// 三重循环
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        vector<int> rec(n+1, 0); // rec[i]表示 arr[0] ^ arr[1] ^ ... ^ arr[i-1]
        for (int i{0}; i < n; ++i) {
            rec[i+1] = rec[i] ^ arr[i];
        }

        int res{0};
        for (int i{0}; i < n; ++i) {
            for (int j{i+1}; j < n; ++j) {
                for (int k{j}; k < n; ++k) {
                    int a = rec[i] ^ rec[j];
                    int b = rec[j] ^ rec[k+1];
                    if (a == b) {
                        ++res;
                    }
                }
            }
        }
        return res;
    }
};

// 三重循环
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        vector<int> rec(n+1, 0); // rec[i]表示 arr[0] ^ arr[1] ^ ... ^ arr[i-1]
        for (int i{0}; i < n; ++i) {
            rec[i+1] = rec[i] ^ arr[i];
        }

        int res{0};
        for (int i{0}; i < n; ++i) {
            for (int j{i+1}; j < n; ++j) {
                for (int k{j}; k < n; ++k) {
                    if (rec[i] == rec[k+1]) {
                        ++res;
                    }
                }
            }
        }
        return res;
    }
};

// 两重循环
// [i+1, k] 的范围内的任意j都行，三元组个数是 k - i
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        vector<int> rec(n+1, 0); // rec[i]表示 arr[0] ^ arr[1] ^ ... ^ arr[i-1]
        for (int i{0}; i < n; ++i) {
            rec[i+1] = rec[i] ^ arr[i];
        }

        int res{0};
        for (int i{0}; i < n; ++i) {
            for (int k{i+1}; k < n; ++k) {
                if (rec[i] == rec[k+1]) {
                    res += k - i;
                }
            }
        }
        return res;
    }
};

// 一重循环 - 哈希表
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        vector<int> s(n+1, 0); // s[i]表示 arr[0] ^ arr[1] ^ ... ^ arr[i-1]
        for (int i{0}; i < n; ++i) {
            s[i+1] = s[i] ^ arr[i];
        }

        int res{0};
        
        unordered_map<int, int> cnt{};   // s[k] 的出现次数
        unordered_map<int, int> total{}; // s[k] 的下标之和
        for (int k{0}; k < n; ++k) {
            if (cnt.count(s[k+1])) {
                res += cnt[s[k+1]] * k - total[s[k+1]];
            }
            ++cnt[s[k]];
            total[s[k]] += k;
        }
        return res;
    }
};

// 一次遍历 - 在计算前缀和的同时计算答案
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        int res{0};
        int s{0}; // 上一个的前缀和
        unordered_map<int, int> cnt{};   // s[k] 的出现次数
        unordered_map<int, int> total{}; // s[k] 的下标之和
        for (int k{0}; k < n; ++k) {
            int val = arr[k];
            if (cnt.count(s ^ val)) {
                res += cnt[s ^ val] * k - total[s ^ val];
            }
            ++cnt[s];
            total[s] += k;
            s ^= val;
        }
        return res;
    }
};

/* 两重循环 - 不用前缀和
a = arr[i] ^ arr[i + 1] ^ ... ^ arr[j - 1]
b = arr[j] ^ arr[j + 1] ^ ... ^ arr[k]
a == b 就可以转换为 a ^ b == 0
也就是 arr[i] ^ arr[i + 1] ^ ... ^ arr[k] == 0
*/
class Solution {
public:
    int countTriplets(vector<int>& arr) {
        int n = arr.size();
        int res{0};
        for (int i{0}; i < n; ++i) {
            int tmp = arr[i];
            for (int k{i + 1}; k < n; ++k) {
                tmp ^= arr[k];
                if (tmp == 0) {
                    res += k - i;
                }
            }
        }
        return res;
    }
};
